class Complie {
    constructor(el, vm) {
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        this.vm = vm;
        if (this.el) {
            // 如果有才开始编译
            /*
                2.编译 => 提取的v-model 和文本 {{}}
                3。把fragment塞到页面中
            */
            //   1.先把这些真实的dom移植到fragment中
            let fragment = this.nodeFragment(this.el);
            this.complie(fragment);
            this.el.appendChild(fragment);
        }
    }

    /*辅助的方法*/
    isElementNode(node) {
        return node.nodeType === 1
    }

    // 判断是不是指令
    isDirective(name) {
        return name.includes('v-')
    }

    /*核心的方法*/
    complie(fragment) {
        let childNodes = fragment.childNodes;
        Array.from(childNodes).forEach(node => {
            if (this.isElementNode(node)) {
                // 是元素节点  还需要继续深入理解
                this.complieElement(node);  // 编译元素

                this.complie(node)
            } else {
                // 文本节点  需要编译文本
                this.complieText(node)
            }
        })
    }

    // 编译元素
    complieElement(node) {
        // 带v-model v-text v-html
        let attrs = node.attributes; // 取出节点属性
        Array.from(attrs).forEach(attr => {
            // 判断属性是不是 v-
            let attrName = attr.name;
            if (this.isDirective(attrName)) {
                // 取到对应的值放到对应节点中
                let expr = attr.value;
                let [,type] = attrName.split('-');
                // node this.vm.$data expr
                ComplieUtil[type](node,this.vm,expr)
            }
        }) // 转数组
    }

    // 编译文本
    complieText(node) {
        //带 {{}}
        let expr = node.textContent; // 取文本中的内容
       let reg = /\{\{([^}]+)\}\}/g; // {{a}} {{b}} {{c}}
        if(reg.test(expr)){
            ComplieUtil['text'](node,this.vm,expr)
        }
    }

    // 将元素插入文档碎片中

    nodeFragment(el) {
        // 将el内容全部放到内存中
        // 文档碎片
        let firstChild;
        let fragment = document.createDocumentFragment();
        while (firstChild = el.firstChild) {
            fragment.appendChild(firstChild)
        }
        return fragment
    }
}


ComplieUtil={
    getVal(vm,expr){
        expr = expr.split('.');
       return expr.reduce((prev,next)=>{
           return prev[next];
        },vm.$data);
    },
    // 获取编译文本后的结果
    getTextVal(vm,expr){
        return expr.replace(/\{\{([^}]+)\}\}/g,(...arguments)=>{
            return this.getVal(vm,arguments[1])
        });
    },

    text(node,vm,expr){   // 文本的处理
        let updateFn = this.undater['textUpdater'];
        // vm.$data[expr]
        let value =  this.getTextVal(vm,expr);
        expr.replace(/\{\{([^}]+)\}\}/g,(...arguments)=>{
            new Wacther(vm,arguments[1],(newValue)=>{
                //当数据一变化会调用 updata
                updateFn && updateFn(node,this.getTextVal())
            });
        });

        updateFn && updateFn(node,value)
    },
    model(node,vm,expr){  // 输入框处理
        let updateFn = this.undater['modelUpdater'];
        // vm.$data[expr]
        // 这里加个监控  数据变化调用wacth callback

        new Wacther(vm,expr,(newValue)=>{
            //当数据一变化会调用 updata
            updateFn && updateFn(node,this.getVal(vm,expr))
        });
        updateFn && updateFn(node,this.getVal(vm,expr))
    },
    undater:{
        // 文本更新
        textUpdater(node,value){
            node.textContent = value
        },
        // 输入框更新
        modelUpdater(node,value){
          node.value = value
        }

    }
};

